Skip to content

ExecutorService

ExecutorService is a framework provided by JDK that simplify the execution of async tasks - It defines a thread pool - The API assign tasks to each thread

ExecutorService is an interface, so is necessary use an its implementation, using the factory method provided by the framework, i.e.:

ExecutorService executor = Executors.newFixedThreadPool(...);
ExecutorService executor = Executors.newCachedThreadPool();

The cached thread pool approach could be very useful for performance matters, because it's possible reuse previous threads. Its factory method create a new object ThreadPoolExecutor:

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

The ThreadPoolExecutor object is a class that extends abstract class AbstractExecutorService that implements interface ExecutorService It requires some parameters (that are defined by the factory method newCachedThreadPool() out of the box):

  • int corePoolSize
  • int maximumPoolSize
  • long keepAliveTime
  • TimeUnit unit
  • BlockingQueue< Runnable > workQueue

From javadoc:

     /***
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue} is null
     ***/
     ```
An ExecutorService can execute Runnable and Callable tasks.

>Both Runnable and Callable are defined for perform async tasks, but in a Runnable operation, the task result is not returned back after its finish. Instead the Callable object is defined for tasks that after its finish return back a result that is necessary handle (i.e. status code for a HTTP operation).

```java
Runnable myRunnableTask = () -> {
    try {
        TimeUnit.MILLISECONDS.sleep(300);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
};

//lambda version
Callable<String> myCallableTask = () -> {
    TimeUnit.MILLISECONDS.sleep(300);
    return "Callable task execution";
};

/* //innerclass callable
Callable<String> myCallableTask =
  new Callable<String>() {
    @Override
    public String call() throws Exception {
      TimeUnit.MILLISECONDS.sleep(300);
      return "Callable task execution";
    }
  };
*/


List<Callable<String>> callableTasksList = new ArrayList<>();
callableTasksList.add(myCallableTask);
callableTasks.add(myCallableTask);
callableTasks.add(myCallableTask);

//execute a runnable task
executorService.execute(myRunnableTask);

//execute single or multi callable tasks and get the result
Future<String> future =
  executorService.submit(callableTask);

List<Future<String>> futures = executorService.invokeAll(callableTasks);
  • execute() is void and it not provides anything to get the result of the task's execution or check the status (if the task is complete or not)

  • submit(), invokeAll() submit the task execution (that could be both Runnable or Callable tasks) to the ExecutorService and return the Future or list of Future object that handle the result of the task's execution.

Managing the Future object, in order to grab the result is possible invoke the method future.get() and is also possible define a time limit for retreive the result: String result = future.get(200, TimeUnit.MILLISECONDS); In order to check the completion status there are several methods as isDone() or isCancelled()